jetcrab\vm\executor/
instruction_dispatcher.rs

1//! # Instruction Dispatcher
2//!
3//! Central dispatcher that routes VM instructions to their appropriate handlers.
4//! This module provides the main execution logic that determines which handler
5//! should process each instruction type.
6//!
7//! ## Architecture
8//!
9//! The dispatcher follows a pattern where each instruction type is mapped to
10//! a specific handler:
11//!
12//! - **Stack Operations**: Handled by `StackOpsHandler`
13//! - **Arithmetic Operations**: Handled by `ArithmeticHandler`
14//! - **Comparison Operations**: Handled by `ComparisonHandler`
15//! - **Control Flow Operations**: Handled by `ControlFlowHandler`
16//! - **Heap Operations**: Handled by `HeapOpsHandler`
17//! - **Builtin Calls**: Handled by `BuiltinCallsHandler`
18//!
19//! ## Execution Flow
20//!
21//! 1. Instruction is received with VM state
22//! 2. Dispatcher matches instruction type
23//! 3. Appropriate handler is called
24//! 4. Result is returned (optional new instruction pointer)
25//!
26//! ## Usage
27//!
28//! ```rust
29//! use jetcrab::vm::executor::instruction_dispatcher::InstructionDispatcher;
30//! use jetcrab::vm::instructions::Instruction;
31//!
32//! let result = InstructionDispatcher::execute_instruction(
33//!     &instruction,
34//!     &mut stack,
35//!     &mut heap,
36//!     &mut variables,
37//!     &mut frame,
38//!     &mut registers,
39//!     &mut builtins,
40//! )?;
41//! ```
42
43use crate::vm::executor::error_handler::ExecutionError;
44use crate::vm::executor::instruction_handlers::{
45    ArithmeticHandler, BuiltinCallsHandler, ComparisonHandler, ControlFlowHandler, HeapOpsHandler,
46    StackOpsHandler,
47};
48use crate::vm::executor::traits::{HeapOperations, StackOperations, VariableManager};
49use crate::vm::frame::Frame;
50use crate::vm::instructions::Instruction;
51use crate::vm::registers::Registers;
52use crate::vm::types::ArraySize;
53use crate::vm::value::Value;
54
55/// Central instruction dispatcher for the VM
56///
57/// Provides a single entry point for executing all VM instructions by
58/// routing them to specialized handlers based on instruction type.
59pub struct InstructionDispatcher;
60
61impl InstructionDispatcher {
62    /// Executes a single VM instruction
63    ///
64    /// Routes the instruction to the appropriate handler based on its type.
65    /// Some instructions may modify the instruction pointer, in which case
66    /// the new pointer is returned.
67    ///
68    /// # Arguments
69    /// * `instruction` - The instruction to execute
70    /// * `stack` - The VM stack for value operations
71    /// * `heap` - The VM heap for object allocation
72    /// * `variable_manager` - Manages local and global variables
73    /// * `frame` - Current execution frame
74    /// * `registers` - VM registers including instruction pointer
75    /// * `builtins` - Built-in function implementations
76    ///
77    /// # Returns
78    /// * `Ok(None)` - Instruction executed normally, continue to next
79    /// * `Ok(Some(ip))` - Instruction executed with jump, use new IP
80    /// * `Err(ExecutionError)` - Execution failed
81    ///
82    /// # Examples
83    ///
84    /// ```rust
85    /// use jetcrab::vm::executor::instruction_dispatcher::InstructionDispatcher;
86    /// use jetcrab::vm::instructions::Instruction;
87    ///
88    /// match InstructionDispatcher::execute_instruction(
89    ///     &Instruction::Add,
90    ///     &mut stack,
91    ///     &mut heap,
92    ///     &mut variables,
93    ///     &mut frame,
94    ///     &mut registers,
95    ///     &mut builtins,
96    /// ) {
97    ///     Ok(None) => println!("Continue to next instruction"),
98    ///     Ok(Some(ip)) => println!("Jump to instruction {}", ip),
99    ///     Err(e) => eprintln!("Execution error: {:?}", e),
100    /// }
101    /// ```
102    pub fn execute_instruction<S, H, V>(
103        instruction: &Instruction,
104        stack: &mut S,
105        heap: &mut H,
106        variable_manager: &mut V,
107        frame: &mut Frame,
108        registers: &mut Registers,
109        builtins: &mut crate::runtime::builtins::Builtins,
110    ) -> Result<Option<usize>, ExecutionError>
111    where
112        S: StackOperations,
113        H: HeapOperations,
114        V: VariableManager,
115    {
116        match instruction {
117            Instruction::PushConst(idx) => {
118                let value = frame.get_constant(*idx).unwrap_or(Value::Undefined);
119                stack.push(value);
120                Ok(None)
121            }
122            Instruction::Pop => {
123                StackOpsHandler::pop(stack)?;
124                Ok(None)
125            }
126            Instruction::Dup => {
127                StackOpsHandler::dup(stack)?;
128                Ok(None)
129            }
130            Instruction::Add => {
131                ArithmeticHandler::add(stack)?;
132                Ok(None)
133            }
134            Instruction::Sub => {
135                ArithmeticHandler::subtract(stack)?;
136                Ok(None)
137            }
138            Instruction::Mul => {
139                ArithmeticHandler::multiply(stack)?;
140                Ok(None)
141            }
142            Instruction::Div => {
143                ArithmeticHandler::divide(stack)?;
144                Ok(None)
145            }
146            Instruction::Mod => {
147                ArithmeticHandler::modulo(stack)?;
148                Ok(None)
149            }
150            Instruction::Exp => {
151                ArithmeticHandler::power(stack)?;
152                Ok(None)
153            }
154            Instruction::Inc => {
155                ArithmeticHandler::increment(stack)?;
156                Ok(None)
157            }
158            Instruction::Dec => {
159                ArithmeticHandler::decrement(stack)?;
160                Ok(None)
161            }
162            Instruction::And => {
163                ComparisonHandler::logical_and(stack)?;
164                Ok(None)
165            }
166            Instruction::Or => {
167                ComparisonHandler::logical_or(stack)?;
168                Ok(None)
169            }
170            Instruction::Not => {
171                ComparisonHandler::logical_not(stack)?;
172                Ok(None)
173            }
174            Instruction::Xor => {
175                ComparisonHandler::bitwise_xor(stack)?;
176                Ok(None)
177            }
178            Instruction::Eq => {
179                ComparisonHandler::equal(stack)?;
180                Ok(None)
181            }
182            Instruction::Ne => {
183                ComparisonHandler::not_equal(stack)?;
184                Ok(None)
185            }
186            Instruction::Lt => {
187                ComparisonHandler::less_than(stack)?;
188                Ok(None)
189            }
190            Instruction::Le => {
191                ComparisonHandler::less_equal(stack)?;
192                Ok(None)
193            }
194            Instruction::Gt => {
195                ComparisonHandler::greater_than(stack)?;
196                Ok(None)
197            }
198            Instruction::Ge => {
199                ComparisonHandler::greater_equal(stack)?;
200                Ok(None)
201            }
202            Instruction::StrictEq => {
203                ComparisonHandler::strict_equal(stack)?;
204                Ok(None)
205            }
206            Instruction::StrictNe => {
207                ComparisonHandler::strict_not_equal(stack)?;
208                Ok(None)
209            }
210            Instruction::LoadGlobal(idx) => {
211                let value = variable_manager
212                    .get_global((*idx).into())
213                    .unwrap_or(&Value::Undefined)
214                    .clone();
215                stack.push(value);
216                Ok(None)
217            }
218            Instruction::StoreGlobal(idx) => {
219                let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
220                variable_manager.set_global((*idx).into(), value);
221                Ok(None)
222            }
223            Instruction::LoadLocal(idx) => {
224                let value = variable_manager
225                    .get_local((*idx).into())
226                    .unwrap_or(&Value::Undefined)
227                    .clone();
228                stack.push(value);
229                Ok(None)
230            }
231            Instruction::StoreLocal(idx) => {
232                let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
233                variable_manager.set_local((*idx).into(), value);
234                Ok(None)
235            }
236            Instruction::LoadArg(idx) => {
237                let value = variable_manager
238                    .get_argument((*idx).into())
239                    .unwrap_or(&Value::Undefined)
240                    .clone();
241                stack.push(value);
242                Ok(None)
243            }
244            Instruction::LoadThisFunction => {
245                let function_handle = frame.function_handle.clone().unwrap_or_else(|| {
246                    crate::vm::handle::FunctionHandle::new(crate::vm::handle::HeapHandleId::new(0))
247                });
248                stack.push(Value::Function(function_handle));
249                Ok(None)
250            }
251            Instruction::LoadThis => {
252                let this_value = frame.this_value.clone().unwrap_or(Value::Undefined);
253                stack.push(this_value);
254                Ok(None)
255            }
256            Instruction::LoadClosureVar(name) => {
257                let value = frame
258                    .closure_vars
259                    .get(name)
260                    .cloned()
261                    .unwrap_or(Value::Undefined);
262                stack.push(value);
263                Ok(None)
264            }
265            Instruction::Jump(target_ip) => {
266                let new_ip =
267                    ControlFlowHandler::jump::<S, V>(stack, registers, (*target_ip).into())?;
268                Ok(Some(new_ip))
269            }
270            Instruction::JumpIfTrue(target_ip) => {
271                let new_ip = ControlFlowHandler::jump_if_true::<S, V>(
272                    stack,
273                    registers,
274                    (*target_ip).into(),
275                )?;
276                Ok(Some(new_ip))
277            }
278            Instruction::JumpIfFalse(target_ip) => {
279                let new_ip = ControlFlowHandler::jump_if_false::<S, V>(
280                    stack,
281                    registers,
282                    (*target_ip).into(),
283                )?;
284                Ok(Some(new_ip))
285            }
286            Instruction::Call(function_index) => {
287                ControlFlowHandler::call::<S, V>(
288                    stack,
289                    registers,
290                    frame,
291                    (*function_index).as_usize().into(),
292                )?;
293                Ok(None)
294            }
295            Instruction::Return => {
296                let new_ip =
297                    ControlFlowHandler::return_from_function::<S, V>(stack, registers, frame)?;
298                Ok(Some(new_ip))
299            }
300            Instruction::NewObject => {
301                HeapOpsHandler::alloc_object(stack, heap)?;
302                Ok(None)
303            }
304            Instruction::NewArray(_size) => {
305                HeapOpsHandler::alloc_array(stack, heap)?;
306                Ok(None)
307            }
308            Instruction::SetProperty => {
309                let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
310                let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
311                let object_handle = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
312
313                if let (Value::String(key), Value::Object(handle)) = (property_key, object_handle) {
314                    HeapOpsHandler::set_object_property(stack, heap, handle, key, value)?;
315                }
316                Ok(None)
317            }
318            Instruction::SetPropertyAssign => {
319                let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
320                let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
321                let object_handle = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
322
323                if let (Value::String(key), Value::Object(handle)) = (property_key, object_handle) {
324                    HeapOpsHandler::set_object_property(stack, heap, handle, key, value)?;
325                }
326                Ok(None)
327            }
328            Instruction::GetProperty => {
329                let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
330                let object_handle = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
331
332                if let (Value::String(key), Value::Object(handle)) = (property_key, object_handle) {
333                    HeapOpsHandler::get_object_property(stack, heap, handle, key)?;
334                }
335                Ok(None)
336            }
337            Instruction::TypeOf => {
338                let value = stack.peek().ok_or(ExecutionError::StackUnderflow)?;
339                let type_name = match value {
340                    Value::Number(_) => "number",
341                    Value::String(_) => "string",
342                    Value::Boolean(_) => "boolean",
343                    Value::Object(_) => "object",
344                    Value::Array(_) => "array",
345                    Value::Function(_) => "function",
346                    Value::Null => "null",
347                    Value::Undefined => "undefined",
348                };
349                stack.push(Value::String(type_name.to_string()));
350                Ok(None)
351            }
352            Instruction::InstanceOf => {
353                let constructor = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
354                let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
355
356                let result = match (value, constructor) {
357                    (Value::Object(_), Value::Function(_)) => true,
358                    _ => false,
359                };
360
361                stack.push(Value::Boolean(result));
362                Ok(None)
363            }
364            Instruction::In => {
365                let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
366                let object = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
367
368                let result = match (object, property_key) {
369                    (Value::Object(handle), Value::String(key)) => {
370                        heap.has_object_property(handle.id(), &key)
371                    }
372                    _ => false,
373                };
374
375                stack.push(Value::Boolean(result));
376                Ok(None)
377            }
378            Instruction::Delete => {
379                let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
380                let object_handle = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
381
382                if let (Value::String(key), Value::Object(handle)) = (property_key, object_handle) {
383                    HeapOpsHandler::remove_object_property(stack, heap, handle, key)?;
384                }
385                Ok(None)
386            }
387            Instruction::New => {
388                let constructor = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
389                if let Value::Function(_) = constructor {
390                    HeapOpsHandler::alloc_object(stack, heap)?;
391                }
392                Ok(None)
393            }
394            Instruction::NewClass => {
395                HeapOpsHandler::alloc_object(stack, heap)?;
396                Ok(None)
397            }
398            Instruction::GetPrototype => {
399                let object = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
400                if let Value::Object(handle) = object {
401                    let prototype = heap
402                        .get_object_property(handle.id(), "__proto__")
403                        .unwrap_or(&Value::Undefined)
404                        .clone();
405                    stack.push(prototype);
406                }
407                Ok(None)
408            }
409            Instruction::SetPrototype => {
410                let prototype = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
411                let object = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
412
413                if let Value::Object(handle) = object {
414                    heap.set_object_property(handle.id(), "__proto__".to_string(), prototype);
415                }
416                Ok(None)
417            }
418            Instruction::Await => {
419                let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
420                stack.push(value);
421                Ok(None)
422            }
423            Instruction::Yield => {
424                let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
425                stack.push(value);
426                Ok(None)
427            }
428            Instruction::Throw => {
429                ControlFlowHandler::throw::<S, V>(stack, registers)?;
430                Ok(None)
431            }
432            Instruction::Try(try_block_size, catch_block_size) => {
433                let new_ip = ControlFlowHandler::try_catch::<S, V>(
434                    stack,
435                    registers,
436                    frame,
437                    (*try_block_size).into(),
438                    (*catch_block_size).into(),
439                )?;
440                Ok(Some(new_ip))
441            }
442            Instruction::Catch => Ok(None),
443            Instruction::Finally => {
444                let new_ip = ControlFlowHandler::finally::<S, V>(stack, registers, frame)?;
445                Ok(Some(new_ip))
446            }
447            Instruction::Spread => {
448                let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
449                stack.push(value);
450                Ok(None)
451            }
452            Instruction::Destructure => Ok(None),
453            Instruction::OptionalChain => Ok(None),
454            Instruction::NullishCoalesce => {
455                let right = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
456                let left = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
457
458                let result = match left {
459                    Value::Null | Value::Undefined => right,
460                    _ => left,
461                };
462
463                stack.push(result);
464                Ok(None)
465            }
466            Instruction::PushNull => {
467                stack.push(Value::Null);
468                Ok(None)
469            }
470            Instruction::PushUndefined => {
471                stack.push(Value::Undefined);
472                Ok(None)
473            }
474            Instruction::PushTrue => {
475                stack.push(Value::Boolean(true));
476                Ok(None)
477            }
478            Instruction::PushFalse => {
479                stack.push(Value::Boolean(false));
480                Ok(None)
481            }
482            Instruction::PushSymbol(idx) => {
483                let symbol = frame
484                    .get_constant(*idx)
485                    .unwrap_or(Value::String("Symbol".to_string()));
486                stack.push(symbol);
487                Ok(None)
488            }
489            Instruction::PushBigInt(idx) => {
490                let bigint = frame.get_constant(*idx).unwrap_or(Value::Number(0.0));
491                stack.push(bigint);
492                Ok(None)
493            }
494            Instruction::CallFunction(_function_index, arg_count) => {
495                ControlFlowHandler::call::<S, V>(stack, registers, frame, (*arg_count).into())?;
496                Ok(None)
497            }
498            Instruction::CallBuiltin(function_name, arg_count) => {
499                BuiltinCallsHandler::call_builtin(
500                    stack,
501                    variable_manager,
502                    builtins,
503                    function_name.clone(),
504                    (*arg_count).into(),
505                )?;
506                Ok(None)
507            }
508            Instruction::RemoveObjectProperty => {
509                let property_key = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
510                let object_handle = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
511
512                if let (Value::String(key), Value::Object(handle)) = (property_key, object_handle) {
513                    HeapOpsHandler::remove_object_property(stack, heap, handle, key)?;
514                }
515                Ok(None)
516            }
517            Instruction::CallObjectMethod(method_name, arg_count) => {
518                let object = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
519                if let Value::Object(handle) = object {
520                    let method = heap
521                        .get_object_property(handle.id(), method_name)
522                        .unwrap_or(&Value::Undefined)
523                        .clone();
524                    stack.push(method);
525                    BuiltinCallsHandler::call_builtin(
526                        stack,
527                        variable_manager,
528                        builtins,
529                        method_name.clone(),
530                        (*arg_count).into(),
531                    )?;
532                }
533                Ok(None)
534            }
535            Instruction::CallArrayMethod(method_name, arg_count) => {
536                let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
537                if let Value::Array(handle) = array {
538                    let method = heap
539                        .get_array_element(handle.id(), ArraySize::new(0))
540                        .unwrap_or(&Value::Undefined)
541                        .clone();
542                    stack.push(method);
543                    BuiltinCallsHandler::call_builtin(
544                        stack,
545                        variable_manager,
546                        builtins,
547                        method_name.clone(),
548                        (*arg_count).into(),
549                    )?;
550                }
551                Ok(None)
552            }
553            Instruction::GetArrayLength => {
554                let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
555                if let Value::Array(handle) = array {
556                    let length = heap.get_array_length(handle.id());
557                    stack.push(Value::Number(length as f64));
558                }
559                Ok(None)
560            }
561            Instruction::RemoveArrayElement(index) => {
562                let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
563                if let Value::Array(handle) = array {
564                    let element = heap
565                        .get_array_element(handle.id(), *index)
566                        .unwrap_or(&Value::Undefined)
567                        .clone();
568                    stack.push(element);
569                }
570                Ok(None)
571            }
572            Instruction::PushArrayElement => {
573                let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
574                let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
575
576                if let Value::Array(handle) = array {
577                    HeapOpsHandler::push_array_element(stack, heap, handle, value)?;
578                }
579                Ok(None)
580            }
581            Instruction::PopArrayElement => {
582                let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
583                if let Value::Array(handle) = array {
584                    let element = heap
585                        .get_array_element(handle.id(), ArraySize::new(0))
586                        .unwrap_or(&Value::Undefined)
587                        .clone();
588                    stack.push(element);
589                }
590                Ok(None)
591            }
592            Instruction::ShiftArrayElement => {
593                let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
594                if let Value::Array(handle) = array {
595                    let element = heap
596                        .get_array_element(handle.id(), ArraySize::new(0))
597                        .unwrap_or(&Value::Undefined)
598                        .clone();
599                    stack.push(element);
600                }
601                Ok(None)
602            }
603            Instruction::UnshiftArrayElement(size) => {
604                let value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
605                let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
606
607                if let Value::Array(handle) = array {
608                    heap.set_array_element(handle.id(), *size, value);
609                }
610                Ok(None)
611            }
612            Instruction::SliceArray(start, end) => {
613                let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
614                if let Value::Array(handle) = array {
615                    let start_idx = usize::from(*start);
616                    let end_idx = usize::from(*end);
617
618                    let mut elements = Vec::new();
619                    for i in start_idx..end_idx {
620                        if let Some(element) =
621                            heap.get_array_element(handle.id(), ArraySize::new(i))
622                        {
623                            elements.push(element.clone());
624                        }
625                    }
626
627                    let new_array = heap.alloc_array();
628                    let new_handle =
629                        crate::vm::handle::HeapHandle::<crate::vm::handle::ArrayEntry>::new(
630                            new_array,
631                        );
632
633                    for (i, element) in elements.iter().enumerate() {
634                        heap.set_array_element(new_array, ArraySize::new(i), element.clone());
635                    }
636
637                    stack.push(Value::Array(new_handle));
638                }
639                Ok(None)
640            }
641            Instruction::ConcatArray(count) => {
642                let mut arrays = Vec::new();
643                for _ in 0..(*count).into() {
644                    let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
645                    if let Value::Array(handle) = array {
646                        arrays.push(handle);
647                    }
648                }
649
650                let result_array = heap.alloc_array();
651                let result_handle =
652                    crate::vm::handle::HeapHandle::<crate::vm::handle::ArrayEntry>::new(
653                        result_array,
654                    );
655
656                let mut index = 0;
657                for array_handle in arrays.iter().rev() {
658                    let length = heap.get_array_length(array_handle.id());
659                    for i in 0..length {
660                        if let Some(element) =
661                            heap.get_array_element(array_handle.id(), ArraySize::new(i))
662                        {
663                            heap.set_array_element(
664                                result_array,
665                                ArraySize::new(index),
666                                element.clone(),
667                            );
668                            index += 1;
669                        }
670                    }
671                }
672
673                stack.push(Value::Array(result_handle));
674                Ok(None)
675            }
676            Instruction::IndexOfArray(_target) => {
677                let target_value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
678                let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
679
680                if let Value::Array(handle) = array {
681                    let length = heap.get_array_length(handle.id());
682                    let mut found_index = -1;
683
684                    for i in 0..length {
685                        if let Some(element) =
686                            heap.get_array_element(handle.id(), ArraySize::new(i))
687                        {
688                            if element == &target_value {
689                                found_index = i as i32;
690                                break;
691                            }
692                        }
693                    }
694
695                    stack.push(Value::Number(found_index as f64));
696                }
697                Ok(None)
698            }
699            Instruction::IncludesArray(_target) => {
700                let target_value = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
701                let array = stack.pop().ok_or(ExecutionError::StackUnderflow)?;
702
703                if let Value::Array(handle) = array {
704                    let length = heap.get_array_length(handle.id());
705                    let mut found = false;
706
707                    for i in 0..length {
708                        if let Some(element) =
709                            heap.get_array_element(handle.id(), ArraySize::new(i))
710                        {
711                            if element == &target_value {
712                                found = true;
713                                break;
714                            }
715                        }
716                    }
717
718                    stack.push(Value::Boolean(found));
719                }
720                Ok(None)
721            }
722            Instruction::Halt => Ok(None),
723        }
724    }
725}